package com.zlx.mall.basic.web.controller;


import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.zlx.mall.basic.common.exception.BizExtraRuntimeException;
import com.zlx.mall.basic.common.exception.BizRuntimeException;
import com.zlx.mall.basic.web.model.BaseResponse;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.server.MethodNotAllowedException;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author qingke
 **/
@Slf4j
@RestControllerAdvice
public class ExceptionController {

    private static final Logger exceptionLogger = LoggerFactory.getLogger("exceptionLogger");

    @ExceptionHandler(value = {Exception.class, Error.class})
    public BaseResponse catchException(Exception e) {

        exceptionLogger.error("> ###### Exception", e);

        if (e instanceof BizExtraRuntimeException) {
            return handleBizExtraStatusException(((BizExtraRuntimeException) e));
        }

        if (e instanceof BizRuntimeException) {
            return handleBizRuntimeException(((BizRuntimeException) e));
        }

        if (e instanceof MethodArgumentNotValidException) {
            return handleMethodArgumentNotValidException(((MethodArgumentNotValidException) e));
        }

        if (e instanceof MethodNotAllowedException ||
                e instanceof HttpRequestMethodNotSupportedException ||
                e instanceof NoHandlerFoundException) {
            // TODO 2023/12/19 19:50 HttpError?
            return BaseResponse.failure();
        }

        log.error("> ###### Unknown Exception", e);

        return BaseResponse.failure();
    }

    private BaseResponse handleBizRuntimeException(BizRuntimeException e) {
        return BaseResponse.failure()
                .status(e.getCode(), e.getMessage());
    }

    private BaseResponse handleBizExtraStatusException(BizExtraRuntimeException e) {
        return BaseResponse.failure()
                .status(e.getCode(), e.getMessage())
                .extra(e.getExtraCode(), e.getExtraMessage());
    }

    /**
     * 处理@Validate or @Valid
     *
     * @param e MethodArgumentNotValidException
     * @return Response
     */
    private BaseResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        String errorMessage = errors.size() == 1 ? errors.get(0).getDefaultMessage() :
                errors.stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(Constants.SEMICOLON));

        return BaseResponse.failure().message(errorMessage);
    }

}
